package com.zl.gmadmin.configuration.secutity.filter;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Sets;
import com.zl.gmadmin.common.Status;
import com.zl.gmadmin.configuration.secutity.ignore.CustomConfig;
import com.zl.gmadmin.service.auth.CustomUserDetailsService;
import com.zl.gmadmin.utils.LogUtil;
import com.zl.gmadmin.utils.ResponseUtil;
import com.zl.gmadmin.utils.jwt.JwtUtil;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;

/**
 * @author zhangliang
 * @version 1.0
 * @date 2021/2/2 12:40
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {


    private final CustomUserDetailsService detailsService;


    private final JwtUtil jwtUtil;


    private final CustomConfig customConfig;

    public JwtAuthenticationFilter(CustomUserDetailsService detailsService, JwtUtil jwtUtil, CustomConfig customConfig) {
        this.detailsService = detailsService;
        this.jwtUtil = jwtUtil;
        this.customConfig = customConfig;
    }

    /**
     * //log.debug(this.getClass().getName()+":{}","jwt拦截器配置");
     * @param httpServletRequest
     * @param httpServletResponse
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

        if (Objects.isNull(customConfig.getIgnoreConfig())) {
            //没有默认配置的
             LogUtil.debug(this.getClass().getName()+":{}","没有白名单");
        }
        if (checkIgnores(httpServletRequest)) {
            LogUtil.debug(this.getClass().getName()+":{}","白名单验证通过");
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }
        String jwt = jwtUtil.getJwtFromRequest(httpServletRequest);
          LogUtil.debug("jwt:"+jwt);

        if (StrUtil.isNotBlank(jwt)) {
             LogUtil.debug(this.getClass().getName()+":{}","jwt拦截配置");
            try {
                String username = jwtUtil.getUsernameFromJWT(jwt);

                UserDetails userDetails = detailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));

                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//                   验证通过才到controller
                LogUtil.debug("授权验证通过");
                filterChain.doFilter(httpServletRequest, httpServletResponse);
            }catch (SecurityException e){
                LogUtil.debug("security异常");
//                ResponseUtil.renderJson(httpServletResponse,e);
            }
        }else {
            LogUtil.debug("我没有jwt，又没有默认权限，所以输出请先登录");

            ResponseUtil.renderJson(httpServletResponse, Status.UNAUTHORIZED,null);
        }

    }


    /**
     * 请求是否不需要进行权限拦截
     *
     * @param request 当前请求
     * @return true - 忽略，false - 不忽略
     */
    private boolean checkIgnores(HttpServletRequest request) {
        String method = request.getMethod();

        HttpMethod httpMethod = HttpMethod.resolve(method);
        if (Objects.isNull(httpMethod)) {
            httpMethod = HttpMethod.GET;
        }

        Set<String> ignores = Sets.newHashSet();

        switch (httpMethod) {
            case GET:
                ignores.addAll(customConfig.getIgnoreConfig().getGet());
                break;
            case PUT:
                ignores.addAll(customConfig.getIgnoreConfig().getPut());
                break;
            case HEAD:
                ignores.addAll(customConfig.getIgnoreConfig().getHead());
                break;
            case POST:
                ignores.addAll(customConfig.getIgnoreConfig().getPost());
                break;
            case PATCH:
                ignores.addAll(customConfig.getIgnoreConfig().getPatch());
                break;
            case TRACE:
                ignores.addAll(customConfig.getIgnoreConfig().getTrace());
                break;
            case DELETE:
                ignores.addAll(customConfig.getIgnoreConfig().getDelete());
                break;
            case OPTIONS:
                ignores.addAll(customConfig.getIgnoreConfig().getOptions());
                break;
            default:
                break;
        }

        ignores.addAll(customConfig.getIgnoreConfig().getPattern());


        if (!ignores.isEmpty()) {
            for (String ignore : ignores) {
                LogUtil.debug("白名单验证");
                AntPathRequestMatcher matcher = new AntPathRequestMatcher(ignore, method);

                if (matcher.matches(request)) {
                    return true;
                }
            }
        }

        return false;
    }
}
